ヒアドキュメントを使ってAWS CLIの –cli-input パラメーターを便利に使う
しばたです。
AWS CLIやAWS Tools for PowerShellはその特性上一つのコマンドで多くのパラメーターを扱うことが多くなります。
この様な場合、PowerShellではスプラッティングを使うとコマンドのパラメーターを宣言的[ref]あくまでもハッシュ定義の宣言での話ですが...[/ref]に記述でき非常に便利です。
私もAWS Tools for PowerShellではスプラッティングを多用し、たとえば以下の様な感じの記述を常用します。
Import-Module AWS.Tools.EC2
Import-Module AWS.Tools.SimpleSystemsManagement
# 例) New-EC2Instance でEC2インスタンスを作成する
# 多数のパラメーターを扱うときはスプラッティングを使い $params 変数にパラメーターの内容を記述
$params = @{
KeyName = 'my-ec2-keypair'
ImageId = $(Get-SSMParameter -Name /aws/service/ami-windows-latest/Windows_Server-2019-Japanese-Full-Base -Region ap-northeast-1 -Select Parameter.Value)
InstanceType = 't3.medium'
MinCount = 1
MaxCount = 1
SubnetId = (Get-EC2Subnet -Filter @{Name = 'tag:Name'; Values = 'my-subnet-name'}).SubnetId
SecurityGroupId = (Get-EC2SecurityGroup -Filter @{Name = 'group-name'; Values = 'my-security-group-name'}).GroupId
EbsOptimized = $false
BlockDeviceMapping = [Amazon.EC2.Model.BlockDeviceMapping]@{
DeviceName = '/dev/sda1'
Ebs = @{
VolumeType = 'gp2'
VolumeSize = 30
DeleteOnTermination = $true
}
}
TagSpecification = @{
ResourceType = 'Instance';
Tags = @( @{Key = 'Name'; value = 'my-windows-server-2019'});
}
}
New-EC2Instance @params
AWS CLIにはCLIスケルトンがある
AWS CLIでスプラッティングは使えませんがAWS CLIにはCLI スケルトンと呼ばれる機能があり、多数のパラメーターをJSONまたはYAMLの形で指定することが可能です。
細かい話は上記記事をご覧いただければと思います。
今回は紹介のために簡単な例を出すと、たとえばaws ec2 describe-images
コマンドでAMIイメージを検索する場合以下の様なJSONをparameters.json
という名前で保存し、
{
"Filters": [
{ "Name": "architecture", "Values": [ "x86_64" ] },
{ "Name": "name", "Values": [ "amzn2-ami-hvm*" ] }
],
"Owners": [ "amazon" ]
}
--cli-input-json
パラメーターでこのJSONファイルを指定して実行することができます。
# parameters.json がカレントディレクトリにある場合の指定例
# ※--queryパラメーターは表示の都合で記述している
aws ec2 describe-images --cli-input-json file://./parameters.json \
--query 'reverse(sort_by(Images, &CreationDate))[0].{Architecture:Architecture, CreationDate:CreationDate, ImageId:ImageId, Name:Name}'
結果この様な感じで現在最新のAmazon Linux 2 AMIイメージを検索できます。
--cli-input パラメーターはヒアドキュメントを受け入れる
ドキュメントやサンプルではこの--cli-input-json
(および--cli-input-yaml
)パラメーターはfile://
スキーマ形式のファイル名を指定していますが、このパラメーターはJSONやYAMLの内容を直接指定しても構いません。
変数で指定してやれば改行込みの文字列も使えます。
以降、BashおよびPowerShellでヒアドキュメントを使った例を紹介します。
検証環境
現時点のAWS CloudShellを検証環境とします。
- AWS CLI 2.0.58
- Bash 4.2.46
- PowerShell 7.0.3
1. Bashでヒアドキュメントを使って--cli-input-jsonを指定
Bashでヒアドキュメントを扱う方法はいくつかあると思いますが今回はcatコマンドを使ったものを採用します。
先述の例は以下の様な感じで--cli-input-json
に$params
変数を渡すことができます。
# params変数にJSONの内容を設定
params=$(cat <<EOM
{
"Filters": [
{ "Name": "architecture", "Values": [ "x86_64" ] },
{ "Name": "name", "Values": [ "amzn2-ami-hvm*" ] }
],
"Owners": [ "amazon" ]
}
EOM
)
# --cli-input-json パラメーターはJSONを直接指定可能
aws ec2 describe-images --cli-input-json "$params" \
--query 'reverse(sort_by(Images, &CreationDate))[0].{Architecture:Architecture, CreationDate:CreationDate, ImageId:ImageId, Name:Name}'
注意点としては$params
変数は"$params"
とダブルクォートでくくる必要がある点くらいです。
2. Bashでヒアドキュメントを使って--cli-input-yamlを指定
CLIスケルトンではJSONだけでなくYAMLも使うことができ、前項と同様に扱えます。
# params変数にYAMLの内容を設定
params=$(cat <<EOM
Filters:
- Name: 'architecture'
Values:
- 'x86_64'
- Name: 'name'
Values:
- 'amzn2-ami-hvm*' # serach Amazon Linux 2
Owners:
- 'amazon'
EOM
)
# --cli-input-yaml パラメーターはYAMLを直接指定可能
aws ec2 describe-images --cli-input-yaml "$params" \
--query 'reverse(sort_by(Images, &CreationDate))[0].{Architecture:Architecture, CreationDate:CreationDate, ImageId:ImageId, Name:Name}'
3. PowerShellでヒアドキュメントを使って--cli-input-jsonを指定
PowerShellでヒアドキュメントは@''@
(または@""@
)で設定でき以下の様な感じで$params
変数を定義できます。
$params = @'
{
"Filters": [
{ "Name": "architecture", "Values": [ "x86_64" ] },
{ "Name": "name", "Values": [ "amzn2-ami-hvm*" ] }
],
"Owners": [ "amazon" ]
}
'@
この変数をそのまま--cli-input-json
に渡すことができれば良かったのですが、残念ながらPowerShellから外部にあるawsコマンドにダブルクォートを引き渡す際はエスケープを要求されていしまいます。
エスケープ無しでawsコマンドを実行すると下図の様にJSON解析エラーになってしまいます。
Error parsing parameter 'cli-input-json': Invalid JSON received.
このためちょっとひと手間(-replace '"','\"'
の部分)かけてやる必要があります。
# PowerShell → awsコマンドに渡す際はダブルクォートのエスケープが必要
# -replace演算子を使って一括エスケープ
$params = @'
{
"Filters": [
{ "Name": "architecture", "Values": [ "x86_64" ] },
{ "Name": "name", "Values": [ "amzn2-ami-hvm*" ] }
],
"Owners": [ "amazon" ]
}
'@ -replace '"','\"'
# --cli-input-json パラメーターはJSONを直接指定可能
aws ec2 describe-images --cli-input-json $params `
--query 'reverse(sort_by(Images, &CreationDate))[0].{Architecture:Architecture, CreationDate:CreationDate, ImageId:ImageId, Name:Name}'
ちなみに-replace
演算子を使ってエスケープした後のJSONはこんな感じになっています。
{
\"Filters\": [
{ \"Name\": \"architecture\", \"Values\": [ \"x86_64\" ] },
{ \"Name\": \"name\", \"Values\": [ \"amzn2-ami-hvm*\" ] }
],
\"Owners\": [ \"amazon\" ]
}
4. PowerShellでヒアドキュメントを使って--cli-input-yamlを指定
最後にPowerShellでYAMLを使った場合の例です。
YAMLではダブルクォートは使わなくても良いのでこちらはエスケープ不要です。
このためPowerShell上ではJSONよりYAMLを使う方が良い気がします。
# YAMLではダブルクォートは必須ではないのでエスケープ不要
# (※もちろんダブルクォートを使った場合は要エスケープ)
$params = @'
Filters:
- Name: 'architecture'
Values:
- 'x86_64'
- Name: 'name'
Values:
- 'amzn2-ami-hvm*' # serach Amazon Linux 2
Owners:
- 'amazon'
'@
# --cli-input-yaml パラメーターはYAMLを直接指定可能
aws ec2 describe-images --cli-input-yaml $params `
--query 'reverse(sort_by(Images, &CreationDate))[0].{Architecture:Architecture, CreationDate:CreationDate, ImageId:ImageId, Name:Name}'
5. (おまけ) PowerShellでスプラッティングを使った場合
これまでの例と同等の処理をAWS Tools for PowerShell + スプラッティングを使った場合は以下の様になります。
$params = @{
Filter = (
@{ Name = 'architecture'; Values = 'x86_64'},
@{ Name = 'name'; Values = 'amzn2-ami-hvm*'}
);
Owner = 'amazon'
}
Get-EC2Image @params |
Sort-Object CreationDate -Descending | Select-Object Architecture, CreationDate, ImageId, Name -First 1
AWS Tools for PowerShellに--query
パラメーターは無いため代わりにSort-Object
とSelect-Object
を使っているものの、これまでの例と似た記述感になってると思うのですがいかがでしょうか?
追記 : PowerShell 7.3からの挙動の変化
PowerShell 7.3から導入された新機能PSNativeCommandArgumentPassing
によりJSONの取り扱い方が変わっています。
$PSNativeCommandArgumentPassing
変数の値がWindows
またはStandard
の場合はJSONをエスケープすると逆にエラーになります。
# NG : PowerShell 7.3以降ではJSONをエスケープしてはダメ
$params = @'
{
"Filters": [
{ "Name": "architecture", "Values": [ "x86_64" ] },
{ "Name": "name", "Values": [ "amzn2-ami-hvm*" ] }
],
"Owners": [ "amazon" ]
}
'@ -replace '"','\"' # -replace 演算子は不要
# OK : PowerShell 7.3以降の場合はこれで良い
$params = @'
{
"Filters": [
{ "Name": "architecture", "Values": [ "x86_64" ] },
{ "Name": "name", "Values": [ "amzn2-ami-hvm*" ] }
],
"Owners": [ "amazon" ]
}
'@
最後に
以上となります。
ちょっとしたテクニックですがCLIの書き方の幅が広がると思いますのでぜひ使ってみてください。